/*
 *
 * Copyright (C) 2012 Walter Lütgenau
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 *      http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 * 
 */
package offset.nodes.client.dialog.schema.view;

import java.util.ResourceBundle;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.jcr.PropertyType;
import javax.jcr.RepositoryException;
import javax.swing.ComboBoxModel;
import javax.swing.JFrame;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
import javax.swing.event.ListDataListener;
import offset.nodes.client.chooser.view.TypeChooserDialog;
import offset.nodes.client.model.NodeTypes;
import offset.nodes.client.virtual.model.SchemaProperty;
import offset.nodes.client.model.SimpleNamespaceRegistry;
import offset.nodes.client.tree.model.TreeNodePanel;
import offset.nodes.client.tree.model.TreeNodePanelContainer;
import offset.nodes.client.model.TreeNodeUserObject;
import offset.nodes.client.virtual.model.jcr.QName;
import offset.nodes.client.virtual.model.jcr.nodetype.NodeTypeDefinition;
import offset.nodes.client.virtual.model.jcr.nodetype.PropertyDefinition;
import offset.nodes.client.virtual.model.jcr.nodetype.ValueConstraintDefinition;
import offset.nodes.client.view.SimpleDialog;
import offset.nodes.client.virtual.model.jcr.SimpleValue;

/**
 *
 * @author  Walter Lütgenau
 */
public class SchemaPropertyPanel extends javax.swing.JPanel implements TreeNodePanel {

    TreeNodeUserObject userObject = null;
    TreeNodePanelContainer container = null;
    TextFieldDocumentListener textFieldDocumentListener = new TextFieldDocumentListener();
    NodeTypes types;
    ValueConstraintDefinition[] valueConstraints = null;
    SimpleNamespaceRegistry namespaces = SimpleNamespaceRegistry.getInstance();

    /** Creates new form SchemaPropertyPanel */
    public SchemaPropertyPanel() {
        initComponents();
    }

    public void setTypes(NodeTypes types) {
        this.types = types;
    }

    class TextFieldDocumentListener implements DocumentListener {

        public void changedUpdate(DocumentEvent e) {
            validateOkButton();
        }

        public void insertUpdate(DocumentEvent e) {
            validateOkButton();
        }

        public void removeUpdate(DocumentEvent e) {
            validateOkButton();
        }
    }

    class PropertyTypeComboBoxModel implements ComboBoxModel {

        class PropertyTypeEntry {

            private int type;
            private String name;

            public PropertyTypeEntry(int type, String name) {
                this.type = type;
                this.name = name;
            }

            @Override
            public String toString() {
                return ResourceBundle.getBundle("offset/nodes/client/dialog/view/DialogBundle").getString("schema.propertyType." + getName());
            }

            public int getType() {
                return type;
            }

            public String getName() {
                return name;
            }
        }
        PropertyTypeEntry[] entries = new PropertyTypeEntry[10];
        int selected;

        public PropertyTypeComboBoxModel() {
            entries[PropertyType.UNDEFINED] = new PropertyTypeEntry(PropertyType.UNDEFINED, PropertyType.TYPENAME_UNDEFINED);
            entries[PropertyType.BINARY] = new PropertyTypeEntry(PropertyType.BINARY, PropertyType.TYPENAME_BINARY);
            entries[PropertyType.BOOLEAN] = new PropertyTypeEntry(PropertyType.BOOLEAN, PropertyType.TYPENAME_BOOLEAN);
            entries[PropertyType.DATE] = new PropertyTypeEntry(PropertyType.DATE, PropertyType.TYPENAME_DATE);
            entries[PropertyType.DOUBLE] = new PropertyTypeEntry(PropertyType.DOUBLE, PropertyType.TYPENAME_DOUBLE);
            entries[PropertyType.LONG] = new PropertyTypeEntry(PropertyType.LONG, PropertyType.TYPENAME_LONG);
            entries[PropertyType.NAME] = new PropertyTypeEntry(PropertyType.NAME, PropertyType.TYPENAME_NAME);
            entries[PropertyType.PATH] = new PropertyTypeEntry(PropertyType.PATH, PropertyType.TYPENAME_PATH);
            entries[PropertyType.REFERENCE] = new PropertyTypeEntry(PropertyType.REFERENCE, PropertyType.TYPENAME_REFERENCE);
            entries[PropertyType.STRING] = new PropertyTypeEntry(PropertyType.STRING, PropertyType.TYPENAME_STRING);
            selected = 0;
        }

        public void setSelectedItem(Object anItem) {
            for (int i = 0; i < entries.length; i++) {
                if (entries[i] == anItem) {
                    selected = i;
                    break;
                }
            }
        }

        public Object getElementAt(int index) {
            return entries[index];
        }

        public void removeListDataListener(ListDataListener l) {
        }

        public void addListDataListener(ListDataListener l) {
        }

        public int getSize() {
            return entries.length;
        }

        public Object getSelectedItem() {
            return entries[selected];
        }
    }

    public TreeNodeUserObject getUserObject() {
        getProperty((SchemaProperty) userObject);
        return userObject;
    }

    public void setPanel(TreeNodeUserObject userObject) {
        this.userObject = userObject;
        setProperty((SchemaProperty) userObject);
    }

    protected void setProperty(SchemaProperty definition) {
        getNameTextField().setText(definition.getName().toString());
        getMandatoryCheckbox().setSelected(definition.getProperty().isMandatory());
        getMultipleCheckbox().setSelected(definition.getProperty().isMultiple());
        getMandatoryCheckbox().setEnabled(true);
        getMultipleCheckbox().setEnabled(true);
        mandatoryLabel.setEnabled(true);
        multipleLabel.setEnabled(true);
        getPropertyTypeCombo().setSelectedIndex(definition.getProperty().getRequiredType());
        getPropertyTypeCombo().repaint();
        valueConstraints = definition.getProperty().getValueConstraints();
        if (valueConstraints.length > 0)
            constraintCheckbox.setSelected(true);
        if (definition.getProperty().getDefaultValues() != null && definition.getProperty().getDefaultValues().length == 1)
            try {
                defaultTextField.setText(definition.getProperty().getDefaultValues()[0].getString());
            } catch (Exception ex) {
                ex.printStackTrace();
            }
        else
            defaultTextField.setText("");
        propertySelected(null);

        validateOkButton();
    }

    protected SchemaProperty getProperty(SchemaProperty definition) {
        String[] names = getNameTextField().getText().split("}");
        QName name = new QName(names[0].substring(1), names[1]);

        PropertyDefinition property = new PropertyDefinition();
        property.setName(name);
        property.setMandatory(getMandatoryCheckbox().isSelected());
        property.setMultiple(getMultipleCheckbox().isSelected());
        property.setRequiredType(getPropertyTypeCombo().getSelectedIndex());
        property.setValueConstraints(valueConstraints);
        if (defaultTextField.getText() != null && defaultTextField.getText().length() > 0)
            try {
                property.setDefaultValues(new SimpleValue[]{new SimpleValue(defaultTextField.getText())});
                property.setAutoCreated(true);
            } catch (RepositoryException ex) {
                ex.printStackTrace();
            }


        definition.setName(name);
        definition.setProperty(property);

        return definition;
    }

    public void setContainer(TreeNodePanelContainer container) {
        this.container = container;
    }

    private void validateOkButton() {
        if (getNameTextField().isEnabled())
            if (!isQName(getNameTextField().getText())) {
                container.enableOkButton(false);
                return;
            }

        container.enableOkButton(true);
    }

    protected boolean isQName(String name) {
        if (name.length() == 0)
            return false;

        String[] parts = name.split("\\{");
        if (parts.length != 2)
            return false;

        parts = name.split("\\}");
        if (parts.length != 2)
            return false;

        return true;
    }

    public javax.swing.JCheckBox getMandatoryCheckbox() {
        return mandatoryCheckbox;
    }

    public void setMandatoryCheckbox(javax.swing.JCheckBox mandatoryCheckbox) {
        this.mandatoryCheckbox = mandatoryCheckbox;
    }

    public javax.swing.JCheckBox getMultipleCheckbox() {
        return multipleCheckbox;
    }

    public void setMultipleCheckbox(javax.swing.JCheckBox multipleCheckbox) {
        this.multipleCheckbox = multipleCheckbox;
    }

    public javax.swing.JTextField getNameTextField() {
        return nameTextField;
    }

    public void setNameTextField(javax.swing.JTextField nameTextField) {
        this.nameTextField = nameTextField;
    }

    public javax.swing.JComboBox getPropertyTypeCombo() {
        return propertyTypeCombo;
    }

    public void setPropertyTypeCombo(javax.swing.JComboBox propertyTypeCombo) {
        this.propertyTypeCombo = propertyTypeCombo;
    }

    /** This method is called from within the constructor to
     * initialize the form.
     * WARNING: Do NOT modify this code. The content of this method is
     * always regenerated by the Form Editor.
     */
    // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
    private void initComponents() {

        nameLabel = new javax.swing.JLabel();
        nameTextField = new javax.swing.JTextField();
        nameTextField.getDocument().addDocumentListener(textFieldDocumentListener);
        mandatoryLabel = new javax.swing.JLabel();
        mandatoryCheckbox = new javax.swing.JCheckBox();
        multipleLabel = new javax.swing.JLabel();
        multipleCheckbox = new javax.swing.JCheckBox();
        propertyTypeLabel = new javax.swing.JLabel();
        propertyTypeCombo = new javax.swing.JComboBox();
        jSeparator1 = new javax.swing.JSeparator();
        constraintCheckbox = new javax.swing.JCheckBox();
        showConstraintButton = new javax.swing.JButton();
        defaultLabel = new javax.swing.JLabel();
        defaultTextField = new javax.swing.JTextField();

        java.util.ResourceBundle bundle = java.util.ResourceBundle.getBundle("offset/nodes/client/dialog/view/DialogBundle"); // NOI18N
        nameLabel.setText(bundle.getString("schema.nodePanel.name")); // NOI18N

        mandatoryLabel.setText(bundle.getString("schema.nodePanel.mandatory")); // NOI18N

        mandatoryCheckbox.setBorder(javax.swing.BorderFactory.createEmptyBorder(0, 0, 0, 0));
        mandatoryCheckbox.setMargin(new java.awt.Insets(0, 0, 0, 0));

        multipleLabel.setText(bundle.getString("schema.nodePanel.multiple")); // NOI18N

        multipleCheckbox.setBorder(javax.swing.BorderFactory.createEmptyBorder(0, 0, 0, 0));
        multipleCheckbox.setMargin(new java.awt.Insets(0, 0, 0, 0));

        propertyTypeLabel.setText(bundle.getString("schema.property.type")); // NOI18N

        propertyTypeCombo.setModel(new PropertyTypeComboBoxModel());
        propertyTypeCombo.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                propertySelected(evt);
            }
        });

        constraintCheckbox.setText(bundle.getString("schema.property.constraint")); // NOI18N
        constraintCheckbox.setEnabled(false);
        constraintCheckbox.setMargin(new java.awt.Insets(0, 0, 2, 2));

        showConstraintButton.setText(bundle.getString("schema.property.string.selectValues")); // NOI18N
        showConstraintButton.setEnabled(false);
        showConstraintButton.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                editConstraint(evt);
            }
        });

        defaultLabel.setText(bundle.getString("schema.property.default")); // NOI18N

        javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
        this.setLayout(layout);
        layout.setHorizontalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(layout.createSequentialGroup()
                .addContainerGap()
                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                    .addGroup(layout.createSequentialGroup()
                        .addComponent(defaultLabel)
                        .addContainerGap(436, Short.MAX_VALUE))
                    .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
                        .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING)
                            .addGroup(layout.createSequentialGroup()
                                .addGap(84, 84, 84)
                                .addComponent(defaultTextField, javax.swing.GroupLayout.DEFAULT_SIZE, 345, Short.MAX_VALUE))
                            .addGroup(javax.swing.GroupLayout.Alignment.LEADING, layout.createSequentialGroup()
                                .addComponent(mandatoryLabel)
                                .addGap(28, 28, 28)
                                .addComponent(mandatoryCheckbox))
                            .addGroup(javax.swing.GroupLayout.Alignment.LEADING, layout.createSequentialGroup()
                                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                                    .addComponent(multipleLabel)
                                    .addComponent(nameLabel))
                                .addGap(44, 44, 44)
                                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                                    .addGroup(layout.createSequentialGroup()
                                        .addComponent(multipleCheckbox)
                                        .addGap(291, 291, 291))
                                    .addComponent(nameTextField, javax.swing.GroupLayout.DEFAULT_SIZE, 345, Short.MAX_VALUE)))
                            .addGroup(javax.swing.GroupLayout.Alignment.LEADING, layout.createSequentialGroup()
                                .addComponent(propertyTypeLabel)
                                .addGap(56, 56, 56)
                                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                                    .addGroup(layout.createSequentialGroup()
                                        .addComponent(constraintCheckbox)
                                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, 191, Short.MAX_VALUE)
                                        .addComponent(showConstraintButton))
                                    .addComponent(propertyTypeCombo, 0, 345, Short.MAX_VALUE)))
                            .addComponent(jSeparator1, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.PREFERRED_SIZE, 429, javax.swing.GroupLayout.PREFERRED_SIZE))
                        .addGap(46, 46, 46))))
        );
        layout.setVerticalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(layout.createSequentialGroup()
                .addGap(31, 31, 31)
                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                    .addComponent(nameLabel)
                    .addComponent(nameTextField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
                .addGap(22, 22, 22)
                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                    .addComponent(mandatoryLabel)
                    .addComponent(mandatoryCheckbox))
                .addGap(23, 23, 23)
                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                    .addComponent(multipleLabel)
                    .addComponent(multipleCheckbox))
                .addGap(27, 27, 27)
                .addComponent(jSeparator1, javax.swing.GroupLayout.PREFERRED_SIZE, 10, javax.swing.GroupLayout.PREFERRED_SIZE)
                .addGap(34, 34, 34)
                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                    .addComponent(propertyTypeLabel)
                    .addComponent(propertyTypeCombo, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
                .addGap(22, 22, 22)
                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                    .addComponent(constraintCheckbox)
                    .addComponent(showConstraintButton))
                .addGap(27, 27, 27)
                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                    .addComponent(defaultLabel)
                    .addComponent(defaultTextField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
                .addContainerGap(34, Short.MAX_VALUE))
        );
    }// </editor-fold>//GEN-END:initComponents

    private void propertySelected(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_propertySelected
        PropertyTypeComboBoxModel.PropertyTypeEntry propertyType = (PropertyTypeComboBoxModel.PropertyTypeEntry) propertyTypeCombo.getModel().getSelectedItem();
        constraintCheckbox.setSelected(false);
        if (propertyType.getType() == PropertyType.STRING) {
            defaultLabel.setEnabled(true);
            defaultTextField.setEnabled(true);
        } else {
            defaultLabel.setEnabled(false);
            defaultTextField.setEnabled(false);
        }
        if (propertyType.getType() == PropertyType.STRING || propertyType.getType() == PropertyType.REFERENCE) {
            constraintCheckbox.setEnabled(true);
            showConstraintButton.setEnabled(true);
        } else {
            constraintCheckbox.setEnabled(false);
            showConstraintButton.setEnabled(false);
        }
    }//GEN-LAST:event_propertySelected

    private void editConstraint(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_editConstraint
        switch (((PropertyTypeComboBoxModel.PropertyTypeEntry) propertyTypeCombo.getModel().getSelectedItem()).getType()) {
            case PropertyType.STRING:
                StringConstraintPanel constraintPanel = new StringConstraintPanel(valueConstraints);
                SimpleDialog stringDialog = new SimpleDialog(new JFrame(), true, constraintPanel);
                stringDialog.setSize(450, 300);
                stringDialog.setVisible(true);

                if (stringDialog.getReturnStatus() == SimpleDialog.OK) {
                    valueConstraints = constraintPanel.getValueConstraints();
                    constraintCheckbox.setSelected(true);
                }

                break;

            case PropertyType.REFERENCE:
                TypeChooserDialog referenceDialog = new TypeChooserDialog(null, true, types.getDefinitions(null));
                if (valueConstraints.length > 0)
                    referenceDialog.setSelectedType(valueConstraints[0].getDefinition());
                referenceDialog.setVisible(true);

                if (referenceDialog.getReturnStatus() == TypeChooserDialog.RET_OK) {
                    constraintCheckbox.setSelected(true);
                    NodeTypeDefinition value = referenceDialog.getDefinition();
                    ValueConstraintDefinition valueConstraint = new ValueConstraintDefinition(namespaces.toPrefixName(value.getName()));
                    valueConstraints = new ValueConstraintDefinition[1];
                    valueConstraints[0] = valueConstraint;
                }

                break;
        }
    }//GEN-LAST:event_editConstraint
    // Variables declaration - do not modify//GEN-BEGIN:variables
    private javax.swing.JCheckBox constraintCheckbox;
    private javax.swing.JLabel defaultLabel;
    private javax.swing.JTextField defaultTextField;
    private javax.swing.JSeparator jSeparator1;
    private javax.swing.JCheckBox mandatoryCheckbox;
    private javax.swing.JLabel mandatoryLabel;
    private javax.swing.JCheckBox multipleCheckbox;
    private javax.swing.JLabel multipleLabel;
    private javax.swing.JLabel nameLabel;
    private javax.swing.JTextField nameTextField;
    private javax.swing.JComboBox propertyTypeCombo;
    private javax.swing.JLabel propertyTypeLabel;
    private javax.swing.JButton showConstraintButton;
    // End of variables declaration//GEN-END:variables
}
